/**
 * Copyright (C) 2008+ Spark Zheng
 *
 * @file	include/global.h
 * @brief       global defines and macros
 * @module      dlib
 * @see		dlib
 * @history     version 0.1.0, Spark initialized.
 */

#ifndef _DLIB_GLOBAL_H
#define _DLIB_GLOBAL_H

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/cdefs.h>
#include <stdint.h>

#if defined (__WORDSIZE)
#define _DLIB_WORDSIZE	__WORDSIZE
#elif      defined (__i386__)	|| defined (__x86) \
	|| defined (_M_IX86)	|| defined (_M_X86)
#define _DLIB_WORDSIZE	32
#elif      defined (__ia64)	|| defined (__ia64__) \
	|| defined (_M_IA64)	|| defined (__amd64) \
	|| defined (__amd64__)	|| defined (_M_AMD64) \
	|| defined (__x86_64)	|| defined (__x86_64__) \
	|| defined (_M_X64)
#define _DLIB_WORDSIZE	64
#else
#error Unknown machine CPU Wordsize detected in global.h
#endif

#if (_DLIB_WORDSIZE == 32)
#define _DLIB_UINT64_FORMAT	"%llu"
#define _DLIB_INT64_FORMAT	"%lld"
#else
#define _DLIB_UINT64_FORMAT	"%lu"
#define _DLIB_INT64_FORMAT	"%ld"
#endif


#include <sys/types.h>
#include <sys/param.h>
	
#if defined (__GLIBC__)
#include <endian.h>
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
#define _DLIB_LITTLE_ENDIAN
#elif (__BYTE_ORDER == __BIG_ENDIAN)
#define _DLIB_BIG_ENDIAN
#elif (__BYTE_ORDER == __PDP_ENDIAN)
#define _DLIB_PDP_ENDIAN
#else
#error Unknown machine endianness detected in global.h.
#endif
#define _DLIB_BYTE_ORDER	__BYTE_ORDER
#elif defined (_BIG_ENDIAN)
#define _DLIB_BIG_ENDIAN
#define _DLIB_BYTE_ORDER	4321
#elif defined (_LITTLE_ENDIAN)
#define _DLIB_LITTLE_ENDIAN
#define _DLIB_BYTE_ORDER	1234
#elif defined (__sparc)		|| defined (__sparc__) \
	|| defined (_POWER)	|| defined (__powerpc__) \
	|| defined (__ppc__)	|| defined(__hpux) \
	|| defined (_MIPSEB)	|| defined (__s390__)
#define _DLIB_BIG_ENDIAN
#define _DLIB_BYTE_ORDER	4321
#elif defined (__i386__)	|| defined (__alpha__) \
	|| defined (__ia64)	|| defined (__ia64__) \
	|| defined (_M_IX86)	|| defined (_M_IA64) \
	|| defined (_M_ALPHA)	|| defined (__amd64) \
	|| defined (__amd64__)	|| defined (_M_AMD64) \
	|| defined (__x86_64)	|| defined (__x86_64__) \
	|| defined (_M_X64)
#define _DLIB_LITTLE_ENDIAN
#define _DLIB_BYTE_ORDER	1234
#else
#error The file global.h needs to be set up for your CPU type.
#endif


/**
 * error handler:
 * strerror()
 * perror()
 */
#include <errno.h>

#include <stdbool.h>
#include <stddef.h>
#include <stdarg.h>

#include <limits.h>

/**
 * Compiler decorations (__GNUC__)
 *	__inline
 *	__THROW
 *	__NTH(fct)
 *	__const / __signed / __volatile
 *	all the macros followed are defined in sys/cdefs.h
 */
/* __attribute__ ((__pure__)) */
#ifndef __pure
#define __pure			__attribute_pure__
#endif
/* __attribute__((__unused__)) */
//#ifndef __unused
//#define __unused		__attribute__((__unused__))
//#endif
/* __attribute__((__nothrow__)) */
#ifndef __nothrow
#define __nothrow		__THROW
#endif
/* __attribute__((__noinline__)) */
#ifndef __noinline
#define __noinline		__attribute_noinline__
#endif
/* __attribute__((__always_inline__)) */
#ifndef __ainline
#define __ainline		__attribute__((__always_inline__))
#endif

/**
 * container_of
 * @brief cast a member of a structure out to the containing structure
 * @param ptr: the pointer to the member.
 * @param type: the type of the container struct this is embedded in.
 * @param member: the name of the member within the struct.
 */
#ifndef offsetof
#define offsetof(type, member)	((size_t)&((type *)0)->member)
#endif
#ifndef container_of
#define container_of(ptr, type, member)	({ \
	typeof(((type *)0)->member) *__mptr = (ptr); \
	(type *)((char *)__mptr - offsetof(type,member));})
#endif

/** likely/unlikely */
#if __GNUC__ < 3 && !defined(__builtin_expect)
#define __builtin_expect(x,y)	(x)
#endif
#ifndef likely
#define likely(x)		(__builtin_expect((x) != 0, 1))
#endif
#ifndef unlikely
#define unlikely(x)		(__builtin_expect((x) != 0, 0))
#endif

/** min/max */
#ifndef dlib_min
#define dlib_min(x,y)	({typeof(x) _x = (x); typeof(y) _y = (y); \
			(void) (&_x == &_y); _x < _y ? _x : _y;})

static inline int dlib_nmin(int *n, ...) {
	int temp, ret = 0, count = *n, flag = *n;
	va_list ap;
	va_start(ap, n);
	while (count > 0) {
		temp = va_arg(ap, int);
		if (flag != count) {
			if (ret > temp) {
				ret = temp;
				*n = flag - count;
			}
		} else {
			ret = temp;
			*n = 0;
		}
		count -= 1;
	}
	va_end(ap);
	return ret;
}
#endif
#ifndef dlib_max
#define dlib_max(x,y)	({typeof(x) _x = (x); typeof(y) _y = (y); \
			(void) (&_x == &_y); _x > _y ? _x : _y;})

static inline int dlib_nmax(int *n, ...) {
	int temp, ret = 0, count= *n, flag = *n;
	va_list ap;
	va_start(ap, n);
	while (count > 0) {
		temp = va_arg(ap, int);
		if (flag != count) {
			if (ret < temp) {
				ret = temp;
				*n = flag - count;
			}
		} else {
			ret = temp;
			*n = 0;
		}
		count -= 1;
	}
	va_end(ap);
	return ret;
}
#endif

#ifndef BUF_LEN
#define BUF_LEN		1024U
#endif

#ifndef PATH_MAX
#ifdef _POSIX_PATH_MAX
#define PATH_MAX	_POSIX_PATH_MAX
#else
#define PATH_MAX	4096U
#endif
#endif

#ifndef PASS
#define PASS	    (void)1
#endif

#ifndef UNUSED_PARAM
#define UNUSED_PARAM(arg)       (void)(arg)
#endif

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x)	   (sizeof(x) / sizeof((x)[0]))
#endif
	
#ifdef __cplusplus
}
#endif
#endif
